﻿using IMath;
using System.Reflection;

namespace h4
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("反射技术实现数学计算接口");
            Console.WriteLine("========================");

            string mathDllPath = @"D:\c#\作业5\ConsoleApp4\Math.dll";

            while (true)
            {
                Console.WriteLine("\n请选择操作：");
                Console.WriteLine("1. 使用反射加载Math程序集并调用方法");
                Console.WriteLine("2. 测试所有数学运算");
                Console.WriteLine("3. 测试异常处理（除零）");
                Console.WriteLine("4. 检查DLL文件是否存在");
                Console.WriteLine("0. 退出");

                string choice = Console.ReadLine();
                if (choice == "0") break;

                switch (choice)
                {
                    case "1":
                        TestReflectionLoad(mathDllPath);
                        break;
                    case "2":
                        TestAllOperations(mathDllPath);
                        break;
                    case "3":
                        TestExceptionHandling(mathDllPath);
                        break;
                    case "4":
                        CheckDllExists(mathDllPath);
                        break;
                    default:
                        Console.WriteLine("无效选择，请重新输入！");
                        break;
                }
            }
        }

        static void TestReflectionLoad(string dllPath)
        {
            try
            {
                Console.WriteLine("\n=== 测试反射加载Math程序集 ===");
                Console.WriteLine($"DLL路径: {dllPath}");

                if (!File.Exists(dllPath))
                {
                    Console.WriteLine("错误: Math.dll文件不存在！");
                    Console.WriteLine("请先编译Math项目生成Math.dll");
                    return;
                }

                // 1. 动态加载Math程序集
                Assembly mathAssembly = Assembly.LoadFrom(dllPath);
                Console.WriteLine("成功加载Math程序集");

                // 2. 获取MathOperations类型
                Type mathType = mathAssembly.GetType("Math.MathOperations");
                if (mathType == null)
                {
                    Console.WriteLine("未找到Math.MathOperations类型");
                    return;
                }
                Console.WriteLine("找到Math.MathOperations类型");

                // 3. 创建实例
                object mathInstance = Activator.CreateInstance(mathType);
                Console.WriteLine("成功创建MathOperations实例");

                // 4. 获取接口类型
                Type interfaceType = typeof(IMathOperations);
                Console.WriteLine("获取IMathOperations接口类型");

                // 5. 检查类型是否实现接口
                if (!interfaceType.IsAssignableFrom(mathType))
                {
                    Console.WriteLine("MathOperations未实现IMathOperations接口");
                    return;
                }
                Console.WriteLine("MathOperations实现了IMathOperations接口");

                // 6. 通过接口调用方法
                Console.WriteLine("\n通过接口调用方法：");
                InvokeThroughInterface(mathInstance, mathType, interfaceType);

            }
            catch (Exception ex)
            {
                Console.WriteLine($"反射加载失败：{ex.Message}");
            }
        }

        static void InvokeThroughInterface(object instance, Type implementationType, Type interfaceType)
        {
            try
            {
                double a = 15.5;
                double b = 3.2;

                // 获取接口的所有方法
                MethodInfo[] interfaceMethods = interfaceType.GetMethods();

                foreach (MethodInfo interfaceMethod in interfaceMethods)
                {
                    try
                    {
                        Console.WriteLine($"调用方法: {interfaceMethod.Name}");

                        // 从实现类获取对应的方法
                        MethodInfo implementationMethod = implementationType.GetMethod(
                            interfaceMethod.Name,
                            new Type[] { typeof(double), typeof(double) });

                        if (implementationMethod == null)
                        {
                            Console.WriteLine($"错误: 在实现类中未找到方法 {interfaceMethod.Name}");
                            continue;
                        }

                        // 使用实现类的方法调用实例
                        object result = implementationMethod.Invoke(instance, new object[] { a, b });
                        Console.WriteLine($"计算: {a} {GetOperator(interfaceMethod.Name)} {b} = {result}");
                    }
                    catch (TargetInvocationException tie)
                    {
                        Console.WriteLine($"错误: {tie.InnerException?.Message}");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"调用失败: {ex.Message}");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"接口调用失败：{ex.Message}");
            }
        }

        static string GetOperator(string methodName)
        {
            return methodName switch
            {
                "Add" => "+",
                "Subtract" => "-",
                "Multiply" => "×",
                "Divide" => "÷",
                _ => "?"
            };
        }

        static void TestAllOperations(string dllPath)
        {
            try
            {
                Console.WriteLine("\n=== 测试所有数学运算 ===");

                if (!File.Exists(dllPath))
                {
                    Console.WriteLine("错误: Math.dll文件不存在！");
                    return;
                }

                // 加载程序集和创建实例
                Assembly mathAssembly = Assembly.LoadFrom(dllPath);
                Type mathType = mathAssembly.GetType("Math.MathOperations");
                object mathInstance = Activator.CreateInstance(mathType);
                Type interfaceType = typeof(IMathOperations);

                // 测试数据
                double[] testValues = { 10.0, 4.0, 8.5, 2.5, 15.0, 3.0 };

                for (int i = 0; i < testValues.Length - 1; i += 2)
                {
                    double a = testValues[i];
                    double b = testValues[i + 1];

                    Console.WriteLine($"\n测试数据: a={a}, b={b}");

                    // 调用所有接口方法
                    MethodInfo[] interfaceMethods = interfaceType.GetMethods();

                    foreach (MethodInfo interfaceMethod in interfaceMethods)
                    {
                        try
                        {
                            // 从实现类获取对应的方法
                            MethodInfo implementationMethod = mathType.GetMethod(
                                interfaceMethod.Name,
                                new Type[] { typeof(double), typeof(double) });

                            if (implementationMethod != null)
                            {
                                object result = implementationMethod.Invoke(mathInstance, new object[] { a, b });
                                Console.WriteLine($"{interfaceMethod.Name}: {result}");
                            }
                        }
                        catch (TargetInvocationException tie)
                        {
                            Console.WriteLine($"{interfaceMethod.Name} 错误: {tie.InnerException?.Message}");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"测试失败：{ex.Message}");
            }
        }

        static void TestExceptionHandling(string dllPath)
        {
            try
            {
                Console.WriteLine("\n=== 测试异常处理（除零运算）===");

                if (!File.Exists(dllPath))
                {
                    Console.WriteLine("错误: Math.dll文件不存在！");
                    return;
                }

                Assembly mathAssembly = Assembly.LoadFrom(dllPath);
                Type mathType = mathAssembly.GetType("Math.MathOperations");
                object mathInstance = Activator.CreateInstance(mathType);

                // 获取除法方法（从实现类获取）
                MethodInfo divideMethod = mathType.GetMethod("Divide", new Type[] { typeof(double), typeof(double) });

                if (divideMethod == null)
                {
                    Console.WriteLine("未找到Divide方法");
                    return;
                }

                // 测试正常除法
                Console.WriteLine("\n1. 测试正常除法：");
                object normalResult = divideMethod.Invoke(mathInstance, new object[] { 10.0, 2.0 });
                Console.WriteLine($"10.0 ÷ 2.0 = {normalResult}");

                // 测试除零异常
                Console.WriteLine("\n2. 测试除零异常：");
                try
                {
                    object zeroResult = divideMethod.Invoke(mathInstance, new object[] { 10.0, 0.0 });
                    Console.WriteLine($"10.0 ÷ 0.0 = {zeroResult}");
                }
                catch (TargetInvocationException tie)
                {
                    Console.WriteLine($"捕获到预期异常：{tie.InnerException?.Message}");
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine($"异常处理测试失败：{ex.Message}");
            }
        }

        static void CheckDllExists(string dllPath)
        {
            Console.WriteLine($"\n检查DLL文件: {dllPath}");

            if (File.Exists(dllPath))
            {
                Console.WriteLine("✓ Math.dll文件存在");

                // 显示文件信息
                FileInfo fileInfo = new FileInfo(dllPath);
                Console.WriteLine($"文件大小: {fileInfo.Length} 字节");
                Console.WriteLine($"创建时间: {fileInfo.CreationTime}");
                Console.WriteLine($"修改时间: {fileInfo.LastWriteTime}");

                // 尝试加载程序集获取版本信息
                try
                {
                    AssemblyName assemblyName = AssemblyName.GetAssemblyName(dllPath);
                    Console.WriteLine($"程序集名称: {assemblyName.Name}");
                    Console.WriteLine($"版本: {assemblyName.Version}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"获取程序集信息失败: {ex.Message}");
                }
            }
            else
            {
                Console.WriteLine("✗ Math.dll文件不存在");
                Console.WriteLine("请执行以下步骤:");
                Console.WriteLine("1. 打开Math项目所在目录");
                Console.WriteLine("2. 使用命令: dotnet build");
                Console.WriteLine("3. 确保在bin/Debug/net8.0目录下生成Math.dll");
            }
        }
    }
}
